package com.zero2oneit.mall.search.mapper.impl;

import com.alibaba.fastjson.JSON;
import com.zero2oneit.mall.common.exception.CustomException;
import com.zero2oneit.mall.common.utils.EsIndexConstant;
import com.zero2oneit.mall.common.utils.StringUtils;
import com.zero2oneit.mall.common.utils.bootstrap.BoostrapDataGrid;
import com.zero2oneit.mall.search.config.ESConfig;
import com.zero2oneit.mall.search.mapper.EsGoodProMapper;
import org.elasticsearch.action.get.*;
import org.elasticsearch.action.search.MultiSearchRequest;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery;

/**
 * @author Lee
 * @date 2021/3/17 -11:28
 */
@Component
public class EsGoodProMapperImpl implements EsGoodProMapper {

    @Autowired
    private RestHighLevelClient client;


    //es搜索的公共方法，查询多个
    public List esSelectList(String index, QueryBuilder query, Class c,String[] arr){
        //1.创建检索请求
        SearchRequest searchRequest = new SearchRequest();
        //指定索引
        searchRequest.indices(index);
        //指定DSl,检索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //查询条件
        FetchSourceContext fetchSourceContext = new FetchSourceContext(true, arr, null);
        searchSourceBuilder.query(query).fetchSource(fetchSourceContext);
        searchSourceBuilder.size(100);
        searchRequest.source(searchSourceBuilder);
        //执行方法
        List list;
        long total;
        try {
            SearchResponse search = client.search(searchRequest, ESConfig.COMMON_OPTIONS) ;
            SearchHits hits = search.getHits();
            total = hits.getTotalHits().value;
            list=new ArrayList((int) total);
            SearchHit[] hit = hits.getHits();
            for (SearchHit documentFields : hit) {
                String sourceAsString = documentFields.getSourceAsString();
                Object object = JSON.parseObject(sourceAsString, c);
                list.add(object);
            }
        } catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        return list;
    }

    @Override
    public boolean exists(String index, String id) {
        GetRequest request = new GetRequest(index,id);
        request.fetchSourceContext(new FetchSourceContext(false));
        boolean exists = false;
        try {
            exists = client.exists(request, ESConfig.COMMON_OPTIONS);
        } catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        return exists;
    }

    @Override
    public GetResponse getById(String index, String id) {
        GetRequest request = new GetRequest(index,id);
        GetResponse response = null;
        try {
            response = client.get(request, ESConfig.COMMON_OPTIONS);
        }catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        return response;
    }

    @Override
    public boolean updateById(String index, String id, long seqNo,long term, String jsonObject) {
        UpdateRequest request = new UpdateRequest(index,id);
        request.doc(jsonObject, XContentType.JSON);
        request.setIfSeqNo(seqNo);
        request.setIfPrimaryTerm(term);
//        UpdateResponse update = null;
        try {
            client.update(request, ESConfig.COMMON_OPTIONS);
        }catch (IOException e) {
            //更细失败
            return false;
        }
//        return update.status()==RestStatus.OK;
        return true;
    }

    @Override
    public Map skuListStock(List<String> list,String index, String[] includes) {
        MultiGetRequest request = new MultiGetRequest();
        FetchSourceContext fetchSourceContext =
                new FetchSourceContext(true, includes, null);
        for (String id : list) {
            request.add(new MultiGetRequest.Item(index, id).fetchSourceContext(fetchSourceContext));
        }
        MultiGetResponse response = null;
        try {
            response = client.mget(request, ESConfig.COMMON_OPTIONS);
        } catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        MultiGetItemResponse[] responses = response.getResponses();
        Map map;
        Map resultMap=new HashMap(list.size());
        for (MultiGetItemResponse respon : responses) {
            String id = respon.getId();
            map = respon.getResponse().getSource();
            resultMap.put(id,map);
    }
        return resultMap;
    }


    @Override
    public Map proListShop(List<Map<String,String>> list,String index) {
        MultiSearchRequest request = new MultiSearchRequest();

        String[] arr={"mainPicture","productPrice"};
        FetchSourceContext fetchSourceContext =
                new FetchSourceContext(true, arr, null);
        for (Map<String,String> id : list) {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchQuery("businessId", id.get("businessId"))).fetchSource(fetchSourceContext);
            searchSourceBuilder.from(1);
            searchSourceBuilder.size(3);
            request.add(new SearchRequest(index).source(searchSourceBuilder));
        }

        MultiSearchResponse response = null;
        try {
            response = client.msearch(request, ESConfig.COMMON_OPTIONS);
        } catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        MultiSearchResponse.Item[] responses = response.getResponses();
        Map resultMap=new HashMap(list.size());
        for (int i = 0; i < responses.length; i++) {
            String s =responses[i].getResponse().toString();
            Map resultList = JSON.parseObject(s,Map.class);
            resultMap.put(list.get(i),resultList);
        }
        return resultMap;
    }

    @Override
    public Map yzSkuList(List<Map> list, String index) {
        MultiSearchRequest request = new MultiSearchRequest();
        FetchSourceContext fetchSourceContext =
                new FetchSourceContext(true, null, null);
        for (Map id : list) {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(30);
            searchSourceBuilder.query(QueryBuilders.boolQuery()
                    .must(termsQuery("productId",id.get("productId"))))
                    .fetchSource(fetchSourceContext);
            request.add(new SearchRequest(index).source(searchSourceBuilder));
        }
        MultiSearchResponse response = null;
        try {
            response = client.msearch(request, ESConfig.COMMON_OPTIONS);
        }catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        MultiSearchResponse.Item[] responses = response.getResponses();
        Map resultMap=new HashMap(list.size());
        for (int i = 0; i < responses.length; i++) {
            SearchHit[] hits = responses[i].getResponse().getHits().getHits();
//            Map resultList = JSON.parseObject(s,Map.class);
            resultMap.put(list.get(i),hits);
        }
        return resultMap;
    }

    @Override
    public Map hotGood() {
        MultiSearchRequest request = new MultiSearchRequest();
        SearchRequest firstSearchRequest = new SearchRequest();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(2);
        FetchSourceContext fetchSourceContext = new FetchSourceContext(true, EsIndexConstant.DESIGNATED_FIELD, null);
        searchSourceBuilder.sort("_score");
        searchSourceBuilder.sort(new FieldSortBuilder("sort").order(SortOrder.ASC));
        searchSourceBuilder.query(QueryBuilders.boolQuery().should(wildcardQuery("plateIds", "9_*"))
                .should(wildcardQuery("plateIds", "*_9_*"))
                .should(wildcardQuery("plateIds", "*_9")).minimumShouldMatch(1)).fetchSource(fetchSourceContext);
        firstSearchRequest.source(searchSourceBuilder);
        firstSearchRequest.indices(EsIndexConstant.GOOD_INDEX);
        request.add(firstSearchRequest);
        SearchRequest secondSearchRequest = new SearchRequest();
        searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(2);
        searchSourceBuilder.sort("_score");
        searchSourceBuilder.sort(new FieldSortBuilder("sort").order(SortOrder.ASC));
        searchSourceBuilder.query(QueryBuilders.boolQuery().should(wildcardQuery("plateIds", "10_*"))
                .should(wildcardQuery("plateIds", "*_10_*"))
                .should(wildcardQuery("plateIds", "*_10")).minimumShouldMatch(1)).fetchSource(fetchSourceContext);
        secondSearchRequest.source(searchSourceBuilder);
        secondSearchRequest.indices(EsIndexConstant.GOOD_INDEX);
        request.add(secondSearchRequest);
        MultiSearchResponse response = null;
        try {
            response = client.msearch(request, ESConfig.COMMON_OPTIONS);
        } catch (IOException e) {
            throw new CustomException("服务器繁忙，请重新刷新");
        }
        SearchHit[] recommendHit = response.getResponses()[0].getResponse().getHits().getHits();
        SearchHit[] hotHit = response.getResponses()[1].getResponse().getHits().getHits();
        Map<String,Object> map=new HashMap<>(2);
        List<Map<String, Object>> recommendHits = Arrays.stream(recommendHit).map(SearchHit::getSourceAsMap).collect(Collectors.toList());
        List<Map<String, Object>> hotHits = Arrays.stream(hotHit).map(SearchHit::getSourceAsMap).collect(Collectors.toList());
        map.put("recommendHit",recommendHits);
        map.put("hotHit",hotHits);
        return map;
    }



    @Override
    //es搜索的公共方法
    public BoostrapDataGrid esSelectCommon(String index, QueryBuilder query, Class c, Integer from, Integer size, String sort, Integer Type){
        //1.创建检索请求
        SearchRequest searchRequest = new SearchRequest();
        //指定索引
        searchRequest.indices(index);
        //指定DSl,检索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //查询条件
        searchSourceBuilder.query(query);
        //排序
        searchSourceBuilder.sort("_score");
        if (!StringUtils.isEmpty(sort)){
            if (sort.equals("DESC")){
                searchSourceBuilder.sort(new FieldSortBuilder("productPrice").order(SortOrder.DESC));
            }else if (sort.equals("ASC")){
                searchSourceBuilder.sort(new FieldSortBuilder("productPrice").order(SortOrder.ASC));
            }else if ("sales".equals(sort)){
                searchSourceBuilder.sort(new FieldSortBuilder("soldStock").order(SortOrder.DESC));
            }else if ("index".equals(sort)){
                searchSourceBuilder.sort(new FieldSortBuilder("sort").order(SortOrder.ASC));
            }
        }
        //分页
        if (from!=null){
            searchSourceBuilder.from(from);
            searchSourceBuilder.size(size);
        }
        //搜索对应字段
        if (Type!=null){
            String[] yzField;
            if (Type!=1){
                yzField= EsIndexConstant.COMMUNITYPRO_FIELD;
            }else {
                yzField= EsIndexConstant.COMMUNITY_FIELD;
            }
            searchSourceBuilder.fetchSource(new FetchSourceContext(true, yzField, null));
        }else {
            searchSourceBuilder.fetchSource(new FetchSourceContext(true, EsIndexConstant.DESIGNATED_FIELD, null));
        }
        searchRequest.source(searchSourceBuilder);
        //执行方法
        List list;
        long total;
        try {
            SearchResponse search = client.search(searchRequest, ESConfig.COMMON_OPTIONS) ;
            SearchHits hits = search.getHits();
            total = hits.getTotalHits().value;
            list=new ArrayList((int) total);
            SearchHit[] hit = hits.getHits();
            for (SearchHit documentFields : hit) {
                String sourceAsString = documentFields.getSourceAsString();
                Object object = JSON.parseObject(sourceAsString, c);
                list.add(object);
            }
        } catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }

        return  new BoostrapDataGrid((int)total, total ==0 ? Collections.EMPTY_LIST :list);
    }
    @Override
    public Map yzProductSku(String skuIndex,String proIndex,String id, String productId) {
        MultiGetRequest request = new MultiGetRequest();
        FetchSourceContext fetchSourceContext = new FetchSourceContext(true, EsIndexConstant.BUYLIMIT_FIELD, null);
        request.add(new MultiGetRequest.Item(skuIndex, id));
        request.add(new MultiGetRequest.Item(proIndex, productId).fetchSourceContext(fetchSourceContext));
        MultiGetResponse response = null;
        try {
            response = client.mget(request, ESConfig.COMMON_OPTIONS);
        } catch (IOException e) {
            throw new CustomException("服务器繁忙");
        }
        MultiGetItemResponse[] responses = response.getResponses();
        Map<String, Object> map = responses[0].getResponse().getSource();
        if (map==null){
            return null;
        }else {
            Map<String, Object> buyLimtMap = responses[1].getResponse().getSource();
            map.put("buyLimit",buyLimtMap.get("buyLimit"));
            map.put("share",buyLimtMap.get("share"));
            map.put("shareTwo",buyLimtMap.get("shareTwo"));
            map.put("reward",buyLimtMap.get("reward"));
            map.put("favourCurrentcy",buyLimtMap.get("favourCurrentcy"));
            map.put("produceTime",buyLimtMap.get("produceTime"));
            map.put("lifeTime",buyLimtMap.get("lifeTime"));
            return map;
        }
    }


}
